﻿using System;
using System.ComponentModel;
using System.Net;
using System.Xml.Linq;
using Appology.SugarSync.Core;
using System.Threading.Tasks;

namespace Appology.SugarSync
{
    public class SugarSyncAccount : INotifyPropertyChanged
    {
        private string _accessKey;
        private string _privateAccessKey;
        
        private long _freeBytes;
        private DateTime? _lastTokenRefresh;
        private string _password;

        private string _token;
        private long _totalBytes;
        private long _usedBytes;
        private string _username;
        
        public string Username
        {
            get { return _username; }
            set
            {
                if (_username != value)
                {
                    _username = value;
                    OnPropertyChanged("Username");
                }
            }
        }

        public long TotalBytes
        {
            get { return _totalBytes; }
            private set
            {
                if (_totalBytes != value)
                {
                    _totalBytes = value;
                    OnPropertyChanged("TotalBytes");
                }
            }
        }

        public long UsedBytes
        {
            get { return _usedBytes; }
            private set
            {
                if (_usedBytes != value)
                {
                    _usedBytes = value;
                    OnPropertyChanged("UsedBytes");
                }
            }
        }

        public long FreeBytes
        {
            get { return _freeBytes; }
            private set
            {
                if (_freeBytes != value)
                {
                    _freeBytes = value;
                    OnPropertyChanged("FreeBytes");
                }
            }
        }

        #region INotifyPropertyChanged Members

        public event PropertyChangedEventHandler PropertyChanged;

        #endregion

        public void SetApiCredentials(string accessKey, string privateAccessKey)
        {
            _accessKey = accessKey;
            _privateAccessKey = privateAccessKey;
        }

        public void SetUserCredentials(string username, string password)
        {
            Username = username;
            _password = password;
        }

        public async Task<bool> AuthenticateAsync()
        {
            await RefreshTokenAsync();
            return _token != null;
        }

        public async Task RefreshAsync()
        {
            var result = await GetXmlAsync(new Uri("https://api.sugarsync.com/user"));

            TotalBytes = Convert.ToInt64(result.Element("quota").Element("limit").Value);
            UsedBytes = Convert.ToInt64(result.Element("quota").Element("usage").Value);
            FreeBytes = TotalBytes - UsedBytes;
        }

        internal async Task<XElement> GetXmlAsync(Uri uri)
        {
            var webClient = await GetWebClientAsync();

            var result = await webClient.DownloadStringTaskAsync(uri);

            var xElement = XElement.Parse(result);

            return xElement;
        }

        internal async Task<WebClient> GetWebClientAsync()
        {
            if (_lastTokenRefresh == null || DateTime.Now.AddMinutes(-5.0) > _lastTokenRefresh.Value)
            {
                await RefreshTokenAsync();
            }

            var webClient = new WebClient();
            webClient.Headers["Authorization"] = _token;

            return webClient;
        }

        internal async Task<HttpWebRequest> GetHttpWebRequestAsync(Uri uri)
        {
            if (_lastTokenRefresh == null || DateTime.Now.AddMinutes(-5.0) > _lastTokenRefresh.Value)
            {
                await RefreshTokenAsync();
            }

            var httpWebRequest = (HttpWebRequest)WebRequest.Create(uri);
            httpWebRequest.Headers["Authorization"] = _token;

            return httpWebRequest;
        }

        private async Task RefreshTokenAsync()
        {
            _token = null;

            XElement authRequest = XElement.Parse("<authRequest/>");
            XElement username = XElement.Parse("<username/>");
            XElement password = XElement.Parse("<password/>");
            XElement accessKeyId = XElement.Parse("<accessKeyId/>");
            XElement privateAccessKey = XElement.Parse("<privateAccessKey/>");

            username.Value = _username;
            password.Value = _password;
            accessKeyId.Value = _accessKey;
            privateAccessKey.Value = _privateAccessKey;

            authRequest.Add(username);
            authRequest.Add(password);
            authRequest.Add(accessKeyId);
            authRequest.Add(privateAccessKey);

            var webClient = new WebClient();
            var x = await webClient.UploadStringTaskAsync(new Uri("https://api.sugarsync.com/authorization"), "POST", authRequest.ToString());

            _token = webClient.ResponseHeaders["Location"];
            _lastTokenRefresh = DateTime.Now;
        }

        protected void OnPropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }
    }
}